from core.Linux import open_monitor,close_monitor
from core.data_monitor import ServerData
from core.data_jmeter import jmeter_data
from core.jmeter_OS import exec_jmeter
from core.data_test import data
from core.Setting import db_win
from core.judeg import judge
from wxy_MySQL import MySQLdb
from wxy_Mail import Mail
import time
import re
import os


def file_name(file_path,suffix=False):
    '''
    提取文件路径中的文件名称
    :param file_path:文件路径
    :param suffix:是否显示后缀名称；True为显示，False为不显示
    :return:文件名称
    '''
    # reg = r'([^<>/\\\|:""\*\?]+\.\w+$)'
    # result = re.compile(reg).findall(path)[0]
    # return result
    (path,full_file_name)=os.path.split(file_path)
    if suffix==True:
        return full_file_name
    else:
        (file_name,ext)=os.path.splitext(full_file_name)
        return file_name


class AUTO:

    TEST_NAME=None                           # 本次测试名称
    DURATION=None                            # jmeter脚本运行时间
    JMETER_PATH=None                         # jmeter脚本路径
    TEST_PATH=None                           # 测试数据存储路径
    DATA_TABLE=None                          # 存储测试数据的数据表
    MONITOR_TABLE_WEB=None                   # 存储监控数据的数据表
    MONITOR_TABLE_MONGO=None                 # 存储监控数据的数据表
    MONITOR_TABLE_REDIS=None                 # 存储监控数据的数据表
    DB = MySQLdb(db_win['host'],
                 db_win['user'],
                 db_win['password'],
                 'performance_testing')      # 存储测试数据和监控数据的数据库


    @staticmethod
    def create_test_data_table():
        '''创建本次测试数据存储表'''
        timestamp = time.strftime("D_%Y%m%d_t%H%M", time.localtime(time.time()))
        table_name = timestamp + '_test_data'
        table_dict = {
            'time':'char(255)',
            'I_id': 'int',
            'I_name': 'char(255)',
            's_time': 'int',
            'e_time': 'int',
            'duration':'int',
            'num_threads': 'int',
            'avg_res_time': 'int',
            'p95_time': 'int',
            'error': 'float',
            'TPS': 'float',
            'web_cpu': 'float',
            'web_memory': 'float',
            'web_tcp':'int',
            'mongo_cpu': 'float',
            'mongo_memory': 'float',
            'mongo_tcp': 'int',
            'redis_cpu': 'float',
            'redis_memory': 'float',
            'redis_tcp': 'int',
        }
        AUTO.DATA_TABLE=table_name                                   # 实例化表名称
        AUTO.DB.create_table(table_name, table_dict)

    @staticmethod
    def SetUp(test_name,
              jmeter_path,
              test_path,
              duration):
        '''

        :param test_name:  本轮测试名称，例如'选课3-28新接口测试'
        :param jmeter_path:
        :param test_path:
        :param duration:
        :return:
        '''

        # 添加所要执行的jmeter脚本(绝对路径)
        if isinstance(jmeter_path,list) is False:
            content='以列表形式导入jmeter脚本;例如["D:\\testing\\jmeter_script1.jmx","D:\\testing\\jmeter_script2.jmx",...]'
            raise Exception(content)
        AUTO.JMETER_PATH=jmeter_path

        # 指定测试文件存储路径
        if isinstance(test_path,str) is False:
            raise Exception('以字符串形式指定测试数据存储路径')
        AUTO.TEST_PATH=test_path

        AUTO.TEST_NAME=test_name
        AUTO.DURATION=duration

    @staticmethod
    def StartTest():
        '''开始测试，创建测试数据存储表'''

        # 创建本次测试数据存储文件夹
        root_path = AUTO.TEST_PATH + '\\{}'.format(AUTO.TEST_NAME)  # 定义当前根目录
        os.mkdir(root_path)

        # 创建测试数据存储表
        AUTO.create_test_data_table()

        # 开启监控
        open_monitor()
        time_stamp=time.strftime('%Y%m%d_%H%M', time.localtime(time.time()))
        AUTO.MONITOR_TABLE_WEB = 'web_monitor_data_{}'.format(str(time_stamp))
        AUTO.MONITOR_TABLE_MONGO = 'mongo_monitor_data_{}'.format(str(time_stamp))
        AUTO.MONITOR_TABLE_REDIS = 'redis_monitor_data_{}'.format(str(time_stamp))

        for i in AUTO.JMETER_PATH:

            # 所测试的脚本文件名称
            i_name=file_name(i)

            # 创建子目录：以接口名称命名
            sub_path = root_path + '\\{}'.format(i_name)  # 以接口名称定义当前子目录
            os.mkdir(sub_path)

            '''创建子目录下的分类目录，分别存放web、redis、mongo服务器监控信息；该接口总体测试信息'''

            web_path=sub_path+'\\web'   # web服务器监控数据 存储路径
            os.mkdir(web_path)
            # web服务器cpu、memory、tcp图片 存储路径
            web_cpu_path=web_path+'\\cpu'
            web_memory_path=web_path+'\\memory'
            web_tcp_path=web_path+'\\tcp'
            os.mkdir(web_cpu_path)
            os.mkdir(web_memory_path)
            os.mkdir(web_tcp_path)

            mongo_path=sub_path+'\\mongo'   # mongo服务器监控数据 存储路径
            os.mkdir(mongo_path)
            # mongo服务器cpu、memory图片 存储路径
            mongo_cpu_path=mongo_path+'\\cpu'
            mongo_memory_path=mongo_path+'\\memory'
            mongo_tcp_path=mongo_path+'\\tcp'
            os.mkdir(mongo_cpu_path)
            os.mkdir(mongo_memory_path)
            os.mkdir(mongo_tcp_path)


            redis_path=sub_path+'\\redis'   # redis服务器监控数据 存储路径
            os.mkdir(redis_path)
            # redis服务器cpu、memory图片 存储路径
            redis_cpu_path=redis_path+'\\cpu'
            redis_memory_path=redis_path+'\\memory'
            redis_tcp_path=redis_path+'\\tcp'
            os.mkdir(redis_cpu_path)
            os.mkdir(redis_memory_path)
            os.mkdir(redis_tcp_path)


            result_path=sub_path+'\\result'   # 测试数据 存储路径
            os.mkdir(result_path)

            '''
            ---------线程变化规则---------
            **********************************************************************************************************
            * 规则1：第二次开始，当前线程数*2，直至线程数达到80
            * 规则2：每次线程数提高20%,即当前线程数*1.2为下次启动线程数
            * 进入规则2，则不会转变至规则1
            * 1.初始线程数为5，对应的序数为I_id为1
            * 3.线程数达到80后，每次线程数提高20%,即当前线程数*1.2为下次启动线程数
            * 4.若再此期间(线程数为5、10、20、40、80)平均响应时间超过700ms，则下次线程数为本次线程数的1.2(即线程数提升20%)
            *
            **********************************************************************************************************
            '''
            # 初始化测试数据
            initial_dict = {
                'judge': True,                 # 判断是否还进行下次测试
                'I_id': 1,                     # 测试次数；初始为1
                'threads': 5,                  # 测试线程数
                'ramp_time': 1,                # 测试线程启动时间
                'duration': AUTO.DURATION,     # jmeter脚本运行时间
                'rule':1,                      # 1:规则1    2：规则2
            }

            temporary_files = sub_path + '\jmeter_temporary_files.csv'    # jmeter临时数据文件路径

            while initial_dict['judge'] == True:

                # 执行指令1：启动jmeter脚本
                CMD1_time = time.strftime("%m-%d  %H:%M:%S", time.localtime(time.time()))   # 当前时间
                CMD_1 = exec_jmeter(i,
                                    temporary_files,
                                    initial_dict['threads'],
                                    initial_dict['ramp_time'],
                                    initial_dict['duration'],
                                    )

                # 执行指令2：处理jmeter数据
                CMD_2 = jmeter_data(temporary_files)
                jmeter_data_dict = {
                    'time': CMD1_time,
                    'I_id': initial_dict['I_id'],
                    'I_name': i_name,
                    's_time': CMD_1[0],
                    'e_time': CMD_1[1],
                    'duration': initial_dict['duration'],
                    'num_threads': initial_dict['threads'],
                    'avg_res_time': CMD_2[0],
                    'p95_time': CMD_2[1],
                    'error': CMD_2[2],
                    'TPS': CMD_2[3],
                }
                AUTO.DB.insert(AUTO.DATA_TABLE, jmeter_data_dict, sql=False)

                # 执行指令3：处理monitor数据
                monitor=ServerData(AUTO.DB,
                                   AUTO.DATA_TABLE,
                                   i_name,
                                   initial_dict['I_id'])


                CMD_3_web = monitor.Web(AUTO.MONITOR_TABLE_WEB,
                                        web_cpu_path,
                                        web_memory_path,
                                        web_tcp_path)
                server_data_dict = {
                    'web_cpu': CMD_3_web[0],
                    'web_memory': CMD_3_web[1],
                    'web_tcp': CMD_3_web[2],
                    # 'mongo_cpu': '',
                    # 'mongo_memory': '',
                    # 'redis_cpu': '',
                    # 'redis_memory': '',
                }
                AUTO.DB.update(AUTO.DATA_TABLE, server_data_dict,
                               'I_name="{}" and I_id={}'.format(i_name, initial_dict['I_id']))


                CMD_3_mongo = monitor.Mongo(AUTO.MONITOR_TABLE_MONGO,
                                            mongo_cpu_path,
                                            mongo_memory_path,
                                            mongo_tcp_path)
                server_data_dict = {
                    # 'web_cpu': '',
                    # 'web_memory': '',
                    'mongo_cpu': CMD_3_mongo[0],
                    'mongo_memory': CMD_3_mongo[1],
                    'mongo_tcp': CMD_3_mongo[2],
                    # 'redis_cpu': '',
                    # 'redis_memory': '',
                }
                AUTO.DB.update(AUTO.DATA_TABLE, server_data_dict,
                               'I_name="{}" and I_id={}'.format(i_name, initial_dict['I_id']))


                CMD_3_redis = monitor.Redis(AUTO.MONITOR_TABLE_REDIS,
                                            redis_cpu_path,
                                            redis_memory_path,
                                            redis_tcp_path)
                server_data_dict = {
                    # 'web_cpu': '',
                    # 'web_memory': '',
                    # 'mongo_cpu': '',
                    # 'mongo_memory': '',
                    'redis_cpu': CMD_3_redis[0],
                    'redis_memory': CMD_3_redis[1],
                    'redis_tcp': CMD_3_redis[2],
                }
                AUTO.DB.update(AUTO.DATA_TABLE, server_data_dict,
                               'I_name="{}" and I_id={}'.format(i_name, initial_dict['I_id']))



                initial_dict['judge'] = judge(AUTO.DB,
                                              AUTO.DATA_TABLE,
                                              'I_id={} and I_name="{}"'.format(initial_dict['I_id'],i_name))  # 判断本次测试结果 bool

                # 若测试继续进行，则修改测试参数
                if initial_dict['judge'] == True:

                    rule={
                        1:5,
                        2:10,
                        3:20,
                        4:40,
                        5:60,
                        6:80,
                    }

                    # 判断执行规则

                    def ramp_time(threads):               # 根据线程数来判断本次ramp_time数值
                        return (threads/100)+1


                    if initial_dict['rule'] == 1:
                        average=AUTO.DB.select(AUTO.DATA_TABLE,
                                               'avg_res_time',
                                               'I_name="{}" and I_id={}'.format(i_name,initial_dict['I_id']))[0]
                        average=int(average)
                        if average > 600:
                            initial_dict['rule'] = 2  # 改变规则
                            initial_dict['threads'] = int(initial_dict['threads'] * 1.2)  # 增加线程数(规则2)
                            initial_dict['ramp_time'] = ramp_time(initial_dict['threads'])
                            initial_dict['I_id'] = initial_dict['I_id'] + 1  # 测试次数+1

                        elif (initial_dict['I_id']+1) in rule.keys():
                            initial_dict['threads'] = rule[initial_dict['I_id']+1]  # 增加线程数(规则1)
                            initial_dict['ramp_time'] = ramp_time(initial_dict['threads'])
                            initial_dict['I_id'] = initial_dict['I_id'] + 1  # 测试次数+1

                        else:
                            initial_dict['rule'] = 2  # 改变规则
                            initial_dict['threads'] = int(initial_dict['threads'] * 1.2)  # 增加线程数(规则2)
                            initial_dict['ramp_time'] = ramp_time(initial_dict['threads'])
                            initial_dict['I_id'] = initial_dict['I_id'] + 1  # 测试次数+1
                    else:
                        initial_dict['threads'] = int(initial_dict['threads'] * 1.2)  # 增加线程数(规则2)
                        initial_dict['ramp_time'] = ramp_time(initial_dict['threads'])
                        initial_dict['I_id'] = initial_dict['I_id'] + 1               # 测试次数+1


                os.remove(temporary_files)

            # 处理 测试数据，存储折线图到指定路径
            data(AUTO.DB,
                 AUTO.DATA_TABLE,
                 'I_name="{}"'.format(i_name),
                 result_path)

        close_monitor()
